<?php
// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: huajie <banhuajie@163.com>
// +----------------------------------------------------------------------
namespace Admin\Controller;

use Admin\Base\Controller;
use OT\File;

/**
 * 在线更新
 * 
 * @author huajie <banhuajie@163.com>
 */
class UpdateController extends Controller
{

    /**
     * 初始化页面
     * 
     * @author huajie <banhuajie@163.com>
     */
    public function index()
    {
        $this->meta_title = '在线更新';
        if (IS_POST) {
            $this->display();
            // 检查新版本
            $version = $this->checkVersion();
            // 在线更新
            $this->update($version);
        } else {
            $this->display();
        }
    }

    /**
     * 检查新版本
     * 
     * @author huajie <banhuajie@163.com>
     */
    private function checkVersion()
    {
        if (extension_loaded('curl')) {
            $url = 'http://www.onethink.cn/index.php?m=home&c=check_version';
            $params = array(
                'version' => ONETHINK_VERSION,
                'domain' => $_SERVER['HTTP_HOST'],
                'auth' => sha1(C('DATA_AUTH_KEY'))
            );
            $vars = http_build_query($params);
            // 获取版本数据
            $data = $this->getRemoteUrl($url, 'post', $vars);
            if (! empty($data) && strlen($data) < 400) {
                $this->showMsg('发现新版本：' . $data, 'success');
                return $data;
            } else {
                $this->showMsg("未发现新版本", 'error');
                exit();
            }
        } else {
            $this->error('请配置支持curl');
        }
    }

    /**
     * 在线更新
     * 
     * @author huajie <banhuajie@163.com>
     */
    private function update($version)
    {
        // PclZip类库不支持命名空间
        import('OT/PclZip');
        
        $date = date('YmdHis');
        $backupFile = I('post.backupfile');
        $backupDatabase = I('post.backupdatabase');
        sleep(1);
        
        $this->showMsg('系统原始版本:' . ONETHINK_VERSION);
        $this->showMsg('OneThink在线更新日志：');
        $this->showMsg('更新开始时间:' . date('Y-m-d H:i:s'));
        sleep(1);
        
        /* 建立更新文件夹 */
        $folder = $this->getUpdateFolder();
        File::mk_dir($folder);
        $folder = $folder . '/' . $date;
        File::mk_dir($folder);
        
        // 备份重要文件
        if ($backupFile) {
            $this->showMsg('开始备份重要程序文件...');
            G('start1');
            $backupallPath = $folder . '/backupall.zip';
            $zip = new \PclZip($backupallPath);
            $zip->create('Application,ThinkPHP,.htaccess,admin.php,index.php');
            $this->showMsg('成功完成重要程序备份,备份文件路径:<a href=\'' . __ROOT__ . $backupallPath . '\'>' . $backupallPath . '</a>, 耗时:' . G('start1', 'stop1') . 's', 'success');
        }
        
        /* 获取更新包 */
        // 获取更新包地址
        $updatedUrl = 'http://www.onethink.cn/index.php?m=home&c=check_version&a=getDownloadUrl';
        $params = array(
            'version' => ONETHINK_VERSION
        );
        $updatedUrl = $this->getRemoteUrl($updatedUrl, 'post', http_build_query($params));
        if (empty($updatedUrl)) {
            $this->showMsg('未获取到更新包的下载地址', 'error');
            exit();
        }
        // 下载并保存
        $this->showMsg('开始获取远程更新包...');
        sleep(1);
        $zipPath = $folder . '/update.zip';
        $downZip = $this->getRemoteUrl($updatedUrl);
        if (empty($downZip)) {
            $this->showMsg('下载更新包出错，请重试！', 'error');
            exit();
        }
        File::write_file($zipPath, $downZip);
        $this->showMsg('获取远程更新包成功,更新包路径：<a href=\'' . __ROOT__ . ltrim($zipPath, '.') . '\'>' . $zipPath . '</a>', 'success');
        sleep(1);
        
        /* 解压缩更新包 */
        // TODO: 检查权限
        $this->showMsg('更新包解压缩...');
        sleep(1);
        $zip = new \PclZip($zipPath);
        $res = $zip->extract(PCLZIP_OPT_PATH, './');
        if ($res === 0) {
            $this->showMsg('解压缩失败：' . $zip->errorInfo(true) . '------更新终止', 'error');
            exit();
        }
        $this->showMsg('更新包解压缩成功', 'success');
        sleep(1);
        
        /* 更新数据库 */
        $updatesql = './update.sql';
        if (is_file($updatesql)) {
            $this->showMsg('更新数据库开始...');
            if (file_exists($updatesql)) {
                $Model = M();
                $sql = File::read_file($updatesql);
                $sql = str_replace("\r\n", "\n", $sql);
                foreach (explode(";\n", trim($sql)) as $query) {
                    $Model->query(trim($query));
                }
            }
            unlink($updatesql);
            $this->showMsg('更新数据库完毕', 'success');
        }
        
        /* 系统版本号更新 */
        $file = File::read_file(COMMON_PATH . 'Common/function.php');
        $file = str_replace(ONETHINK_VERSION, $version, $file);
        $res = File::write_file(COMMON_PATH . 'Common/function.php', $file);
        if ($res === false) {
            $this->showMsg('更新系统版本号失败', 'error');
        } else {
            $this->showMsg('更新系统版本号成功', 'success');
        }
        sleep(1);
        
        $this->showMsg('##################################################################');
        $this->showMsg('在线更新全部完成，如有备份，请及时将备份文件移动至非web目录下！', 'success');
    }

    /**
     * 获取远程数据
     * 
     * @author huajie <banhuajie@163.com>
     */
    private function getRemoteUrl($url = '', $method = '', $param = '')
    {
        $opts = array(
            CURLOPT_TIMEOUT => 20,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_URL => $url,
            CURLOPT_USERAGENT => $_SERVER['HTTP_USER_AGENT']
        );
        if ($method === 'post') {
            $opts[CURLOPT_POST] = 1;
            $opts[CURLOPT_POSTFIELDS] = $param;
        }
        
        /* 初始化并执行curl请求 */
        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        $data = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);
        return $data;
    }

    /**
     * 实时显示提示信息
     * 
     * @param string $msg
     *            提示信息
     * @param string $class
     *            输出样式（success:成功，error:失败）
     * @author huajie <banhuajie@163.com>
     */
    private function showMsg($msg, $class = '')
    {
        echo "<script type=\"text/javascript\">showmsg(\"{$msg}\",\"{$class}\")</script>";
        flush();
        ob_flush();
    }

    /**
     * 生成更新文件夹名
     * 
     * @author huajie <banhuajie@163.com>
     */
    private function getUpdateFolder()
    {
        $key = sha1(C('DATA_AUTH_KEY'));
        return 'update_' . $key;
    }
}